import player, boat, pirates, logging, world, wind

class PirateGame(object):
    """Manages a whole game, and manages its state. Tracks game-level rules,
    turns, phases, etc.
    """
    logger = logging.getLogger('engine.PirateGame')

    _windGen = wind.WindGenerator()
    _nextWeatherChange = 1
    _nextWeather = None
    weather = None
    players = []
    turn = 0
    
    # Current game state
    #NOTE: Movement is plotted, nothing else is.
    (STOPPED,
     PRE_TURN,
     WAITING_PLAYERS_TURNS,
     WAITING_MY_TURN,
     EXECUTING_TURNS,
     EXECUTING_ATTACKS,
     POST_TURN) = range(7)
     
    state = STOPPED
    
    def __init__(self):
        self.ocean = world.World({}, self)
        self.playerTurns = []
    
    def doPreTurn(self):
        """
        Get the game ready for a new turn. Takes an event to set when done.
        """
        self.logger.debug('Starting pre-turn')
        self.turn += 1
        
        self.logger.debug('Updating the weather')
        if self._nextWeather is None:
            self.weather = self._windGen.getNextWind()
            self._nextWeather = self._windGen.getNextWind()
            
        if self.turn == self._nextWeatherChange:
            #Change the wind to the next one, regenerate.
            self.weather = self._nextWeather
            while self._nextWeather == self.weather:
                self._nextWeather = self._windGen.getNextWind()
                self._nextWeatherChange += 1
                
        self.logger.debug('Updating players')
        self.playerTurns = []
        for i in range(len(self.players)):
            self.playerTurns.append(self.players[i])
            self.players[i].startTurn()
            
        self.logger.debug('Pre-turn done')

        
    def doMovementPhase(self):
        """
        Used to execute the movement phase of the current turn.
        """
        self.logger.debug('Beginning movement phase.')

        for p in self.players:
            p.move()

        self.logger.debug('Movement phase finished.')
    
    def iterMoves(self):
        """
        Used to execute the movement phase of the current turn, animating the 
        ships. Returns a generator to allow the client to react between steps.
        """
        self.logger.debug('Beginning animated movement phase.')

        gens = [(player, player.animMove()) for player in self.players]
        while len(gens):
            player, iter = gens.pop(0)
            try:
                ship, newPos = iter.next()
            except StopIteration:
                pass
            else:
                yield player, ship, newPos
                gens.append((player, iter))
        
        self.logger.debug('Animated movement phase finished.')
    
    def doCrewActionPhase(self):
        """
        Used to execute the crew action phase of the current turn.
        This includes weighing/setting anchor, performing repairs,
        upgrades, boarding/disembarking, loading/unloading, etc.
        as well as combat actions.  Basically, all of the activities.
        """
        self.logger.debug('Beginning crew action phase.')

        for p in self.players:
            p.crewActions()

        self.logger.debug('Crew action finished.')
        
    def doTriggerPhase(self):
        """
        Used to execute the trigger response phase of the current turn.
        """
        self.logger.debug('Beginning trigger phase.')

        for p in self.players:
            pass

        self.logger.debug('Trigger phase finished.')
     
    __movementIter = None    
    def tick(self, curT):
        """
        Updates the game state, based on the changes.
        """
        if self.state != 3:
            self.logger.debug('Current state: %s' % self.state)
        if self.state == self.STOPPED:
            return
        
        if self.state == self.PRE_TURN:
            self.doPreTurn()
            self.state = self.WAITING_MY_TURN
            self.logger.debug('Waiting for player to complete turn.')

            
        elif self.state in (self.WAITING_PLAYERS_TURNS,
                            self.WAITING_MY_TURN):
            if len(self.playerTurns) == 0:
                self.state = self.EXECUTING_TURNS

        
        elif self.state == self.EXECUTING_TURNS:
            # TODO: Make this multiple calls
            #       eg. moveShips()
            #           moveSharks()
            #           eatSailors()
            #           etc.
            self.logger.debug('Executing turns.')
            if self.__movementIter is None:
                #First-time only calls
                self.__movementIter = self.iterMoves()
                self.doCrewActionPhase()
            try:
                #Every time calls
                p, ship, newPos = self.__movementIter.next()
                self.onLeg(p, ship, newPos)
            except StopIteration:
                self.state = self.POST_TURN
                self.__movementIter = None
            
            
        elif self.state == self.POST_TURN:
            self.doPostTurn()
            self.state = self.PRE_TURN
    
    def onLeg(self, player, boat, pos):
        """ Just a hook. """
        pass
    
    def onPlayerFinished(self, fplayer):
        if fplayer in self.playerTurns:
            self.playerTurns.remove(fplayer)
        if len(self.playerTurns) == 0:
            self.state = self.EXECUTING_TURNS
    
    def doPostTurn(self):
        """ Respond to triggers. """
        self.doTriggerPhase()
        
    def addPlayer(self, newPlayer=None):
        """
        Adds a new player to the current game.
        """
        if self.state != self.STOPPED:
            return
    
        if newPlayer is None:
            self.logger.debug('Creating player to add...')
            newPlayer = player.Player(self, self.ocean)
        
            self.logger.debug('Creating boat, captain, and crew')
            # TODO: This is just for testing.  Players should pick
            #       their own boat type from an initial list.
            boatClass = 1
            newboat = boat.Boat('%ic' % boatClass, self.ocean, newPlayer)
            # Add the captain as the player (i.e. no boss)
            captain = pirates.randomCaptain(0)
            newboat.crew.append(captain)
            # Add the crew.
            newboat.crew.extend([pirates.randomPirate(captain, i+1)
                                 for i in range(4 * boatClass)])
            # TODO: Find a balanced means of skilled pirate assignment.
            newboat.crew.extend([pirates.randomSkilledPirate(captain, 4*boatClass+i+1)
                                 for i in range(boatClass)])
            
            # Make sure they're all on the ship in the beginning.
            for member in newboat.crew:
                member.parent = newboat
            
            self.logger.debug('Setting money')
            newPlayer.money += 100
            
        self.logger.debug('Adding player and returning.')
        self.players.append(newPlayer)            
        return newPlayer
    
    def start(self):
        if self._nextWeather is None:
            self._nextWeather = self._windGen.getNextWind()
        self.state = self.PRE_TURN
        
    def stop(self):
        self.state = self.STOPPED
    
    def forceCollision(self, object1, object2):
        #Cannot be implemented until client-server relations are known
        pass
